package SSF.App.DDoS;

import java.io.*;
import java.util.*;

/** Tempararily used Destination List tool in DDoS trace back.
 * List desination IP addresses. This one filter out long-last flows 
 */
public class DestList_2 extends BasicPlayer
{
    /** some constants*/
    public static final int SET_QUERY_FAIL = -1;
    public static final int SET_QUERY_SUCC = 0;
    public static final int VERY_SHORT_FLOW = 5;

    /** store information of related src/dest pair */
    protected Hashtable destTable;

    /** start time */
    protected float startTime=0;

    /** end time */
    protected float endTime=Float.MAX_VALUE;

    private int netFlowTypeCode=-1;

    public DestList_2(String streamID)
    {
	super(streamID);
	destTable = new Hashtable();
    }

    /**
     * This is called to set the parameters for query.
     */
    public int setQuery(float startTime, float endTime)
    {
	this.startTime = startTime;
	this.endTime = endTime;

	if (startTime >= endTime) {
	    System.err.println("Invalid startTime/endTime.");
	    return SET_QUERY_FAIL;
	}
	return SET_QUERY_SUCC;
    }
    
    @Override
	public int receive(int type_code, int source_code, double timestamp, 
		       byte[] bytes, int offset, int length)
    {
	//check type
	if (netFlowTypeCode == -1) {
	    netFlowTypeCode = getRecordTypeCode("SSF.OS.NetFlow");
	}
	if (type_code != netFlowTypeCode) {
	    return 0;             // not a netflow record
	}

	// construct flow
	IpNetFlowWD flow = new IpNetFlowWD();
	flow.readFromBytes(bytes, length);

	// check whether it's within the time period
	if (flow.Last < startTime || flow.First > endTime) {
	    return 0;             // out of the time window.
	}

	//!!!!! FIXME: try to just examine short flows !!!!!!
	// filter out long flows
	if (flow.dPkts > VERY_SHORT_FLOW)
	    return 0;

	Integer dKey = new Integer(flow.dstAddr);
	TraceInfo tinfo = (TraceInfo)destTable.get(dKey);
	if (tinfo == null) {
	    tinfo = new TraceInfo(flow.dstAddr, flow.dOctets, flow.dPkts);
	    destTable.put(dKey, tinfo);
	} else
	    tinfo.update(flow.dOctets, flow.dPkts);
	return 0;
    }

    /**
     * print out the content and a summary of ingress/egress table
     */
    public void printSummary()
    {
	System.out.println("--------- destination list  ---------");
	TraceInfo tinfo;
	for (Enumeration enum = destTable.elements();
	     enum.hasMoreElements();)
	    System.out.println(((TraceInfo)enum.nextElement()).toString_2());

	System.out.println("-------------------------------------");
    }


    public static void main(String[] args)
    {
	float startTime = 0;
	float endTime = Float.MAX_VALUE;
	String srcFileName=null;
	int targetIP=0;
	String streamID=null;

	// get argument.
	try {
	    switch (args.length) {
	    case 5:
		if (!args[0].equals("-t"))
		    usageError();
		startTime = Float.valueOf(args[1]).floatValue();
		endTime = Float.valueOf(args[2]).floatValue();
		srcFileName = args[3];
		streamID = args[4];
		break;
	    case 2:
		srcFileName = args[0];
		streamID = args[1];
		break;
	    default:
		usageError();
	    }
	} catch (Exception any) {
	    System.err.println("Error in parameter.");
	    System.err.println(any.getMessage());
	    usageError();
	}

	//for debug
	System.out.println("parameter check passed.");
	DestList_2 destList = new DestList_2(streamID);
      	destList.setQuery(startTime, endTime);

	try {
	    destList.connectRead(srcFileName);
	} catch (streamException se) {
	    System.err.println(se.getMessage());
	    se.printStackTrace();
	    System.exit(-1);
	}
	destList.printSummary();
    }

    private static void usageError()
    {
	System.err.println("usage: java DestList_2 [-t startTime endTime] <netflow file> <streamID>");
	System.exit(-1);
    }
}
